%{
#include <stdio.h>
#include <string.h>
#include "arbre_evaluation.h"
#include "instruction.h"
#include "tabSymbole.h"

int numLigne = 0;
instruction * last_inst;
instruction * parc_i;
algo * algo_current;

extern algo * list_algo;

%}

%token ALGORITHME STR FIN_FICHIER
%token ENTIER
%token VARIABLE
%token ACTION
%token FONCTION
%token CONSTANTE
%token SI SINON SINONSI FINSI TANTQUE FINTANTQUE DEBUT FIN ALORS FAIRE VIR ET OU
%token INF SUP INFEGAL SUPEGAL EGALEGAL NONEGAL
%token PAR_OUV PAR_FER PAR

%union {
	int val;
	char * cha;
	struct symbole * symbole;
	struct arbre * arb;
	struct instruction * in;
	struct fonction * f;
}

%type<cha> STR 
%type<val> ENTIER
%type<symbole> VARIABLE ACTION CONSTANTE FONCTION
%type<arb> EXP condition
%type<in> instruction instructions affectation DEF_ACTION def_inst
%type<f> DEF_FONCTION

%%

algorithmes : algorithme { 
				//afficher(algo_current->ts);
				algo_current->suivant = list_algo; 
				list_algo = algo_current;
			} algorithmes 
			| FIN_FICHIER {return 0;}
			| ;

algorithme : ALGORITHME {
				algo_current = (algo *) malloc(sizeof(struct algo));
				initTab(algo_current->ts);
				//printf("\n-------\nINIT OK\n-------\n");
			} STR { 
				//printf("\n-------\nNOM ALGO DEBUT OK\n-------\n");
				algo_current->nom = $3;
				symbole * s = malloc(sizeof(struct symbole));
				s->nom = $3;
				s->type = SYMBOLE_ALGO;
				//printf("\n-------\nNOM ALGO MILIEU OK\n-------\n");
				instruction * i =  malloc(sizeof(struct instruction));
				s->instruction = i;
				inserer(algo_current->ts,s);
				
				
				instruction * t =  malloc(sizeof(struct instruction));
				t->list1 = i;
				
				parc_i=t;
				
				last_inst = parc_i->list1;
				
				
				//printf("\n-------\nNOM ALGO OK\n-------\n");
				
			} DEBUT instructions FIN

DEF_FONCTION : FONCTION PAR_OUV EXP PAR_FER {
			arbre * a = (arbre *)malloc(sizeof(struct arbre));
			feuille * f = (feuille*) malloc(sizeof(struct feuille));
			noeud * n = (noeud*) malloc(sizeof(struct noeud));
			fonction * fo = (fonction*) malloc(sizeof(struct fonction));
			n=NULL;
			a->f = f;
			a->n = n;
			if((int)$1->valeur==FONCTION_ESTLIBRE){
				fo->type = FCT_ESTLIBRE;
			}else if((int)$1->valeur==FONCTION_NECTAR){
				fo->type = FCT_NECTAR;
			}else {	
				fo->type = -1;	
			}
			fo->param1 = $3;
			f->fonction = fo;
			if(fo->type!=-1)
				$$ = fo;
			else {
				free(a);
				free(f);
				free(fo);
				yyerror("Fonction non reconnue");
			}
		}
		| FONCTION PAR_OUV EXP VIR EXP PAR_FER {
			arbre * a = (arbre *)malloc(sizeof(struct arbre));
			feuille * f = (feuille*) malloc(sizeof(struct feuille));
			noeud * n = (noeud*) malloc(sizeof(struct noeud));
			n=NULL;
			fonction * fo = (fonction*) malloc(sizeof(struct fonction));
			a->f = f;
			a->n = n;
			if((int)$1->valeur==FONCTION_GRILLE){ 
				fo->type = FCT_GRILLE;
			}else if((int)$1->valeur==FONCTION_FLEUR){
				fo->type = FCT_FLEUR;
			}else if((int)$1->valeur==FONCTION_ENNEMIE){ 
				fo->type = FCT_ENNEMIE;
			}else{
				fo->type = -1;
			}
			fo->param1 = $3;
			fo->param2 = $5;
			f->fonction = fo;
			if(fo->type!=-1)
				$$ = fo;
			else {
				free(a);
				free(f);
				free(fo);
				yyerror("Fonction non reconnue");
			}
		}
		| FONCTION PAR_OUV EXP VIR EXP VIR EXP VIR EXP PAR_FER {
			arbre * a = (arbre *)malloc(sizeof(struct arbre));
			feuille * f = (feuille*) malloc(sizeof(struct feuille));
			noeud * n = (noeud*) malloc(sizeof(struct noeud));
			n=NULL;
			fonction * fo = (fonction*) malloc(sizeof(struct fonction));
			a->f = f;
			a->n = n;
			if((int)$1->valeur==FONCTION_DISTANCE){
				fo->type = FCT_DISTANCE;
			}else{
				fo->type = -1;
			}
			fo->param1 = $3;
			fo->param2 = $5;
			fo->param3 = $7;
			fo->param4 = $9;
			f->fonction = fo;
			if(fo->type!=-1)
				$$ = fo;
			else {
				free(a);
				free(f);
				free(fo);
				yyerror("Fonction non reconnue");
			}
		}

EXP : ENTIER {
			arbre * a = (arbre *)malloc(sizeof(struct arbre));
			feuille * f = (feuille*) malloc(sizeof(struct feuille));
			noeud * n = (noeud*) malloc(sizeof(struct noeud));
			n=NULL;
			
			a->f = f;
			a->n = n;
			f->val = $1;
			symbole * s = (symbole *) malloc(sizeof(struct symbole));
			s=NULL;
			fonction * fon = (fonction *) malloc(sizeof(struct fonction));
			fon=NULL;
			f->variable=s;
			f->fonction=fon;
			
			$$ = a;
		}
| DEF_FONCTION {
			arbre * a = (arbre *)malloc(sizeof(struct arbre));
			feuille * f = (feuille*) malloc(sizeof(struct feuille));
			noeud * n = (noeud*) malloc(sizeof(struct noeud));
			n=NULL;
			a->f = f;
			a->n = n;
			f->fonction = $1;
			symbole * s = (symbole *) malloc(sizeof(struct symbole));
			s=NULL;
			f->variable=s;
			
			$$ = a;
		}
| VARIABLE {
			arbre * a = (arbre *)malloc(sizeof(struct arbre));
			feuille * f = (feuille*) malloc(sizeof(struct feuille));
			noeud * n = (noeud*) malloc(sizeof(struct noeud));
			symbole * s = (symbole *) malloc(sizeof(struct symbole));
			fonction * fon = (fonction *) malloc(sizeof(struct fonction));
			n=NULL;
			fon=NULL;
			a->f = f;
			f->fonction=fon;
			a->n = n;
			//affiche_arbre(a);
			s = $1;
			f->variable = $1;
			
			//printf("TOTOTO VAR\n%d\n", t);
			
			if($1->type!=SYMBOLE_VARIABLE_USER)
				$$ = a;
			else
				$$ = (arbre *)$1->valeur;
			
		}
| CONSTANTE {
			arbre * a = (arbre *)malloc(sizeof(struct arbre));
			feuille * f = (feuille*) malloc(sizeof(struct feuille));
			noeud * n = (noeud*) malloc(sizeof(struct noeud));
			symbole * s = (symbole *) malloc(sizeof(struct symbole));
			fonction * fon = (fonction *) malloc(sizeof(struct fonction));
			n=NULL;
			fon=NULL;
			a->f = f;
			f->fonction=fon;
			a->n = n;
			//affiche_arbre(a);
			f->variable = $1;
			
			if($1->type!=SYMBOLE_VARIABLE_USER)
				$$ = a;
			else
				$$ = (arbre *)$1->valeur;
				
	
}
| EXP '+' EXP {
			arbre * a = (arbre *)malloc(sizeof(struct arbre));
			noeud * n = (noeud *)malloc(sizeof(struct noeud));
			feuille * f = (feuille*) malloc(sizeof(struct feuille));
			f=NULL;
			a->f = f;
			
			n->operateur = OP_PLUS;
			n->fg = $1;
			n->fd = $3;
			a->n = n;
			
			$$ = a;
		}
| EXP '-' EXP {
			arbre * a = (arbre *)malloc(sizeof(struct arbre));
			noeud * n = (noeud *)malloc(sizeof(struct noeud));
			feuille * f = (feuille*) malloc(sizeof(struct feuille));
			f=NULL;
			a->f = f;
			
			n->operateur = OP_MOINS;
			n->fg = $1;
			n->fd = $3;
			a->n = n;
			
			$$ = a;	
		}
| EXP '*' EXP {
			arbre * a = (arbre *)malloc(sizeof(struct arbre));
			noeud * n = (noeud *)malloc(sizeof(struct noeud));
			feuille * f = (feuille*) malloc(sizeof(struct feuille));
			f=NULL;
			a->f = f;
			
			n->operateur = OP_MULTI;
			n->fg = $1;
			n->fd = $3;
			a->n = n;
			
			$$ = a;
		}
| EXP '/' EXP {
			arbre * a = (arbre *)malloc(sizeof(struct arbre));
			noeud * n = (noeud *)malloc(sizeof(struct noeud));
			feuille * f = (feuille*) malloc(sizeof(struct feuille));
			f=NULL;
			a->f = f;
			
			n->operateur = OP_DIV;
			n->fg = $1;
			n->fd = $3;
			a->n = n;
			
			$$ = a;	
		}
| EXP '%' EXP {
			arbre * a = (arbre *)malloc(sizeof(struct arbre));
			noeud * n = (noeud *)malloc(sizeof(struct noeud));
			feuille * f = (feuille*) malloc(sizeof(struct feuille));
			f=NULL;
			a->f = f;
			
			n->operateur = OP_MOD;
			n->fg = $1;
			n->fd = $3;
			a->n = n;
			
			$$ = a;	
		}

condition : PAR_OUV EXP INF EXP PAR_FER { 
					arbre * a = (arbre *)malloc(sizeof(struct arbre));
					noeud * n = (noeud *)malloc(sizeof(struct noeud));
					feuille * f = (feuille*) malloc(sizeof(struct feuille));
					f=NULL;
					a->f = f;
					a->n = n;
					n->operateur = OP_INF;
					n->fg = $2;
					n->fd = $4;
					
					
					$$ = a;
			}
			| PAR_OUV EXP SUP EXP PAR_FER {
					arbre * a = (arbre *)malloc(sizeof(struct arbre));
					noeud * n = (noeud *)malloc(sizeof(struct noeud));
					feuille * f = (feuille*) malloc(sizeof(struct feuille));
					f=NULL;
					a->f = f;
					n->operateur = OP_SUP;
					n->fg = $2;
					n->fd = $4;
					int t = (int) $2;
					//printf("Eval : %d\n",evaluer_arbre($2));
					
					a->n = n;
					
					$$ = a;
			}
			| PAR_OUV EXP INFEGAL EXP PAR_FER {
					arbre * a = (arbre *)malloc(sizeof(struct arbre));
					noeud * n = (noeud *)malloc(sizeof(struct noeud));
					feuille * f = (feuille*) malloc(sizeof(struct feuille));
					f=NULL;
					a->f = f;
					n->operateur = OP_INFEGAL;
					n->fg = $2;
					n->fd = $4;
					
					a->n = n;
					
					$$ = a;
			}
			| PAR_OUV EXP SUPEGAL EXP PAR_FER {
					arbre * a = (arbre *)malloc(sizeof(struct arbre));
					feuille * f = (feuille*) malloc(sizeof(struct feuille));
					f=NULL;
					a->f = f;
					noeud * n = (noeud *)malloc(sizeof(struct noeud));
					n->operateur = OP_SUPEGAL;
					n->fg = $2;
					n->fd = $4;
					
					a->n = n;
					
					$$ = a;
			}
			| PAR_OUV EXP EGALEGAL EXP PAR_FER {
					arbre * a = (arbre *)malloc(sizeof(struct arbre));
					noeud * n = (noeud *)malloc(sizeof(struct noeud));
					feuille * f = (feuille*) malloc(sizeof(struct feuille));
					f=NULL;
					a->f = f;
					n->operateur = OP_EGALEGAL;
					n->fg = $2;
					n->fd = $4;
					
					a->n = n;
					
					$$ = a;
			}
			| PAR_OUV EXP NONEGAL EXP PAR_FER {
					arbre * a = (arbre *)malloc(sizeof(struct arbre));
					noeud * n = (noeud *)malloc(sizeof(struct noeud));
					feuille * f = (feuille*) malloc(sizeof(struct feuille));
					f=NULL;
					a->f = f;
					n->operateur = OP_NONEGAL;
					n->fg = $2;
					n->fd = $4;
					
					a->n = n;
					
					$$ = a;	
			}
			| PAR_OUV condition ET condition PAR_FER {
					arbre * a = (arbre *)malloc(sizeof(struct arbre));
					noeud * n = (noeud *)malloc(sizeof(struct noeud));
					feuille * f = (feuille*) malloc(sizeof(struct feuille));
					f=NULL;
					a->f = f;
					a->n = n;
					n->operateur = OP_AND;
					n->fg = $2;
					n->fd = $4;
					//affiche_arbre($2);
					
					$$ = a;	
			}
			| PAR_OUV condition OU condition PAR_FER {
					arbre * a = (arbre *)malloc(sizeof(struct arbre));
					noeud * n = (noeud *)malloc(sizeof(struct noeud));
					feuille * f = (feuille*) malloc(sizeof(struct feuille));
					f=NULL;
					a->f = f;
					n->operateur = OP_OR;
					n->fg = $2;
					n->fd = $4;
					
					a->n = n;
					
					$$ = a;	
			}

affectation : STR EGALEGAL EXP {
				symbole * s = (symbole *)malloc(sizeof(struct symbole));
				s->nom = $1;
				s->type = SYMBOLE_VARIABLE_USER;
				s->valeur = (arbre *)$3;
				
				inserer(algo_current->ts,s);
				
				instruction * i =  malloc(sizeof(struct instruction));
				i->type_instruction = INSCTRUCTION_VAR;
				i->s = s;
				i->condition1 = $3;
				
				$$ = i;
				
				
				
			}
			| VARIABLE EGALEGAL EXP {
				
				instruction * i =  malloc(sizeof(struct instruction));
				i->type_instruction = INSCTRUCTION_VAR;
				i->s = $1;
				$1->valeur = (arbre *)$3;
				i->condition1 = $3;
				
				$$ = i;
				
			}

DEF_ACTION : ACTION PAR {
				if($1->valeur == (int *)ACTION_DEPLACER) {
					yyerror("Action DEPLACER a besoin de 2 paramètres");
				} else {
	
					instruction * i =  malloc(sizeof(struct instruction));
					instruction * t =  malloc(sizeof(struct instruction));
					i->type_instruction = INSCTRUCTION_ACTION;
					i->s = $1;
					t=NULL;
					i->suivante = t;
					
					$$=i;
				}
		}
		| ACTION PAR_OUV EXP VIR EXP PAR_FER {
				instruction * i =  malloc(sizeof(struct instruction));
				instruction * t =  malloc(sizeof(struct instruction));
				i->type_instruction = INSCTRUCTION_ACTION;
				i->s = $1;
				t=NULL;
				i->suivante = t;
				i->condition1 = $3;
				i->condition2 = $5;
				
				$$=i;
		}
		
instructions : instruction {
				//ajout de l'instruction dans la table d'instructions
				//printf("INST : %d \n\n", last_inst->precedente->type_instruction);
				
				last_inst->suivante = $1;
				last_inst = last_inst->suivante;
				
				
			} instructions
			| {}
			;

def_inst : SI {
				instruction * i = (instruction *)malloc(sizeof(struct instruction));
				i->type_instruction = INSCTRUCTION_COND;
				instruction * t = (instruction *)malloc(sizeof(struct instruction));
				instruction * c = (instruction *)malloc(sizeof(struct instruction));
				parc_i->suivante = t;
				i->list1 = c;
				t->precedente = parc_i;
				parc_i = parc_i->suivante;
				parc_i->list1 = i->list1;
				last_inst = parc_i->list1;
				$$ = i;
			}
			| TANTQUE {
				instruction * i = (instruction *)malloc(sizeof(struct instruction));
				i->type_instruction = INSCTRUCTION_COND;
				i->type_action_cond = ACTION_COND_TANTQUE;
				instruction * t = (instruction *)malloc(sizeof(struct instruction));
				instruction * c = (instruction *)malloc(sizeof(struct instruction));
				parc_i->suivante = t;
				i->list1 = c;
				t->precedente = parc_i;
				parc_i = parc_i->suivante;
				parc_i->list1 = i->list1;
				last_inst = parc_i->list1;
				$$ = i;
			}

instruction : affectation {
				$$ = $1;
			}
			| DEF_ACTION {
				$$=$1;
			}
			| def_inst condition ALORS instructions FINSI { 
				// ajout dans la lite d'instructions de l'instruction
				
				//printf("\n\n ---- TEST ---- \n\n");
				//printf("INST : %d \n\n", $1->type_instruction);
				
				$1->type_action_cond = ACTION_COND_SI;
				$1->condition1 = $2;
				$1->list1 = parc_i->list1;
				parc_i = parc_i->precedente;
				free(parc_i->suivante);
				//instruction * temp = malloc(sizeof(struct instruction));
				if(parc_i->list3!=NULL) {
					//printf(" ----- LISTE 3 ---- \n");
					last_inst = parc_i->list3;
				} else if(parc_i->list2!=NULL) {
					last_inst = parc_i->list2;
				} else {
					last_inst = parc_i->list1;
				}
				
				while(last_inst->suivante!=NULL)
					last_inst = last_inst->suivante;
				
				$$ = $1;
			}
			| def_inst condition ALORS instructions SINON{
				
				instruction * c = (instruction *)malloc(sizeof(struct instruction));
				parc_i->list2 = c;
				last_inst=parc_i->list2;
				//printf("\nTEST\n");
			} instructions FINSI { 
				// ajout dans la lite d'instructions de l'instruction
				//printf("\nTEST\n");
				$1->type_action_cond = ACTION_COND_SI_SINON;
				$1->condition1 = $2;
				$1->list1 = parc_i->list1;
				$1->list2 = parc_i->list2;
				parc_i = parc_i->precedente;
				free(parc_i->suivante);
				if(parc_i->list3!=NULL) {
					//printf(" ----- LISTE 3 ---- \n");
					last_inst = parc_i->list3;
				} else if(parc_i->list2!=NULL) {
					last_inst = parc_i->list2;
				} else {
					last_inst = parc_i->list1;
				}
				
				while(last_inst->suivante!=NULL)
					last_inst = last_inst->suivante;
					
				$$ = $1;
			}
			| def_inst condition ALORS instructions SINONSI{
				instruction * c = (instruction *)malloc(sizeof(struct instruction));
				parc_i->list2 = c;
				last_inst=parc_i->list2;
			} condition ALORS instructions SINON{
				instruction * c = (instruction *)malloc(sizeof(struct instruction));
				parc_i->list3 = c;
				last_inst=parc_i->list3;
			} instructions FINSI { 
				// ajout dans la lite d'instructions de l'instruction 
				
				$1->type_action_cond = ACTION_COND_SI_SINON_SI;
				$1->condition1 = $2;
				$1->list1 = parc_i->list1;
				$1->condition2 = $7;
				$1->list2 = parc_i->list2;
				$1->list3 = parc_i->list3;
				parc_i = parc_i->precedente;
				free(parc_i->suivante);
				if(parc_i->list3!=NULL) {
					//printf(" ----- LISTE 3 ---- \n");
					last_inst = parc_i->list3;
				} else if(parc_i->list2!=NULL) {
					last_inst = parc_i->list2;
				} else {
					last_inst = parc_i->list1;
				}
				while(last_inst->suivante!=NULL)
					last_inst = last_inst->suivante;
					
				$$ = $1;
			}
			| def_inst condition FAIRE instructions FINTANTQUE{ 
				// ajout dans la lite d'instructions de l'instruction 
				$1->condition1 = $2;
				
				//printf("TOTO---\n%s\n---\n",$2->n->fg->f->variable->nom);
				//affiche_arbre($2);
				$1->list1 = parc_i->list1;
				parc_i = parc_i->precedente;
				free(parc_i->suivante);
				if(parc_i->list3!=NULL) {
					//printf(" ----- LISTE 3 ---- \n");
					last_inst = parc_i->list3;
				} else if(parc_i->list2!=NULL) {
					last_inst = parc_i->list2;
				} else {
					last_inst = parc_i->list1;
				}
				while(last_inst->suivante!=NULL)
					last_inst = last_inst->suivante;
					
				$$ = $1;
			}

				
%%
